/**
 * Copyright 2009 Adam Ruggles.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.google.code.sapien.action.admin;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.interceptor.validation.SkipValidation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.code.sapien.interceptor.UserAware;
import com.google.code.sapien.model.Category;
import com.google.code.sapien.model.CategoryAcl;
import com.google.code.sapien.model.Role;
import com.google.code.sapien.model.User;
import com.google.code.sapien.security.CategoryPermissions;
import com.google.code.sapien.security.RequiresAdministrator;
import com.google.code.sapien.security.RolePermissions;
import com.google.code.sapien.service.CategoryAclService;
import com.google.code.sapien.service.CategoryService;
import com.google.code.sapien.service.RoleService;
import com.google.inject.Inject;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.validator.annotations.RequiredStringValidator;
import com.opensymphony.xwork2.validator.annotations.Validations;

/**
 * Admin Role Action, used to administer user roles.
 * @author Adam
 * @version $Id: RoleAction.java 30 2010-01-10 19:05:55Z a.ruggles $
 * 
 * Created on Mar 8, 2009 at 9:47:20 PM 
 */
@Validations(
		requiredStrings = {
				@RequiredStringValidator(fieldName = "name",
						message = "Required Field.", key = "validation.required"),
				@RequiredStringValidator(fieldName = "description",
						message = "Required Field.", key = "validation.required")
		} 
)
public class RoleAction extends ActionSupport implements ModelDriven<Role>,	UserAware {
	/**
     * The <code>Logger</code> is used by the application to generate a log messages.
     */
    private static final Logger LOG = LoggerFactory.getLogger(RoleAction.class);

	/**
	 * Serial Version UID.
	 */
	private static final long serialVersionUID = 6659997025839323472L;

	/**
	 * A list of ACLs assigned to this role.
	 */
	private List<CategoryAcl> categoryAcls = new ArrayList<CategoryAcl>();

	/**
	 * The category ACL service.
	 */
	private final CategoryAclService categoryAclService;

	/**
	 * A map of categories to category permissions. 
	 */
	private Map<Category, CategoryPermissions> categoryMap = new HashMap<Category, CategoryPermissions>();

	/**
	 * The category service.
	 */
	private final CategoryService categoryService;

	/**
	 * The logged in user.
	 */
	private User currentUser;

	/**
	 * Role entity data model.
	 */
	private Role role = new Role();

	/**
	 * A list of roles.
	 */
	private List<Role> roles = new ArrayList<Role>();

	/**
	 * The role service.
	 */
	private final RoleService roleService;

	/**
	 * Constructs a role action.
	 * @param roleService The role service.
	 */
	@Inject
	public RoleAction(final RoleService roleService, final CategoryAclService categoryAclService,
			final CategoryService categoryService) {
		super();
		this.roleService = roleService;
		this.categoryAclService = categoryAclService;
		this.categoryService = categoryService;
	}

	/**
	 * Prepares the role add page.
	 * @return SUCCESS.
	 */
	@Action("new-role")
	@RequiresAdministrator
	@SkipValidation
	public String add() {
		return SUCCESS;
	}
	/**
	 * Creates a role.
	 * @return SUCCESS.
	 */
	@Action(value = "create-role", results = {
			@Result(name = "input", location = "new-role.jsp"),
			@Result(name = "success", location = "role.jsp")
			}
	)
	@RequiresAdministrator
	public String create() {
		roleService.add(role, currentUser);
		addActionMessage(this.getText("create-role.success", "The role was created successfully."));
		return execute();
	}

	/**
	 * Prepares the role edit page.
	 * @return SUCCESS.
	 */
	@Action("edit-role")
	@RequiresAdministrator
	@SkipValidation
	public String edit() {
		role = roleService.get(role.getId());
		categoryAcls = categoryAclService.list(role);
		for (Category category : categoryService.getAll()) {
			categoryMap.put(category, new CategoryPermissions());
		}
		for (CategoryAcl acl : categoryAcls) {
			// Can Read is a transient field.
			acl.getPermissions().setCanRead(true);
			categoryMap.put(acl.getCategory(), acl.getPermissions());
		}
		LOG.debug("role info {}", role);
		return SUCCESS;
	}

	/**
	 * Prepares the role page.
	 * @return SUCCESS.
	 * @see com.opensymphony.xwork2.ActionSupport#execute()
	 */
	@Override @SkipValidation
	@RequiresAdministrator
	public String execute() {
		roles = roleService.getAll();
		return SUCCESS;
	}

	/**
	 * Returns categoryAcls.
	 * @return the categoryAcls.
	 */
	public List<CategoryAcl> getCategoryAcls() {
		return categoryAcls;
	}

	/**
	 * Returns categoryMap.
	 * @return the categoryMap.
	 */
	public Map<Category, CategoryPermissions> getCategoryMap() {
		return categoryMap;
	}

	/**
	 * {@inheritDoc}
	 * @see com.opensymphony.xwork2.ModelDriven#getModel()
	 */
	public Role getModel() {
		return role;
	}

	/**
	 * Returns roles.
	 * @return the roles.
	 */
	public List<Role> getRoles() {
		return roles;
	}

	/**
	 * Removes a role.
	 * @return SUCCESS;
	 */
	@Action(value = "remove-role", results = {
			@Result(name = "success", location = "role.jsp")
			}
	)
	@RequiresAdministrator
	@SkipValidation
	public String remove() {
		roleService.remove(role, currentUser);
		addActionMessage(this.getText("remove-role.success", "The role was removed successfully."));
		return execute();
	}

	/**
	 * Sets categoryAcls.
	 * @param categoryAcls the categoryAcls to set.
	 */
	public void setCategoryAcls(final List<CategoryAcl> categoryAcls) {
		this.categoryAcls = categoryAcls;
	}

	/**
	 * {@inheritDoc}
	 * @see com.google.code.sapien.interceptor.UserAware#setCurrentUser(User)
	 */
	public void setCurrentUser(final User currentUser) {
		this.currentUser = currentUser;
	}

	/**
	 * Updates a role.
	 * @return SUCCESS;
	 */
	@Action(value = "update-role", results = {
			@Result(name = "input", location = "edit-role.jsp"),
			@Result(name = "success", location = "role.jsp")
			}
	)
	@RequiresAdministrator
	public String update() {
		roleService.update(role, currentUser);
		addActionMessage(this.getText("update-role.success", "Your updates were saved successfully."));
		return execute();
	}
}
